﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using __ts.Core.Log;
using __ts.Core.Package;
using SevenZip;

namespace CCU.Update
{
    public partial class Installer : Form
    {
        /// <summary>
        /// 解压前执行的文件
        /// </summary>
        private static string extractBeforeFile = "extractBefore.bat";
        /// <summary>
        /// 解压后执行的文件
        /// </summary>
        private static string extractAfterFile = "extractAfter.bat";
        /// <summary>
        /// 配置文件
        /// </summary>
        private static string configFile = "package.xml";
        /// <summary>
        /// 待安装列表
        /// </summary>
        private Dictionary<string, DownloadPackageInfo> pks;
        /// <summary>
        /// 解压路径集合
        /// </summary>
        private Hashtable extractpaths { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pks"></param>
        public Installer(Dictionary<string, DownloadPackageInfo> pks)
        {
            this.pks = pks;
            extractpaths = new Hashtable();
            InitializeComponent();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Installer_Load(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            IDictionaryEnumerator enumerator = this.pks.GetEnumerator();
            while (enumerator.MoveNext())
            {
                DownloadPackageInfo p = enumerator.Value as DownloadPackageInfo;
                if (p.state == 3)
                {
                    if (!File.Exists(p.savePath))
                    {
                        backgroundWorker1.ReportProgress(0, "can't find the local package.");
                        continue;
                    }
                    backgroundWorker1.ReportProgress(0, "=> to install [" + p.id + "]");
                    string dir = Path.GetDirectoryName(p.savePath) + "\\" + p.id;
                    Directory.CreateDirectory(dir);

                    // 1,解压package的配置文件
                    backgroundWorker1.ReportProgress(0, "extracting config files.");
                    SevenZipExtractor sZip = new PackageExtractor().SevenZipExtractor(p.savePath);

                    FileStream fs = new FileStream(dir + "\\" + configFile, FileMode.Create, FileAccess.ReadWrite);
                    sZip.ExtractFile(configFile, fs);
                    fs.Flush();

                    if (sZip.ArchiveFileNames.IndexOf(extractBeforeFile) > -1)
                    {
                        fs = new FileStream(dir + "\\" + extractBeforeFile, FileMode.Create, FileAccess.ReadWrite);
                        sZip.ExtractFile(extractBeforeFile, fs);
                        fs.Flush();
                    }

                    if (sZip.ArchiveFileNames.IndexOf(extractAfterFile) > -1)
                    {
                        fs = new FileStream(dir + "\\" + extractAfterFile, FileMode.Create, FileAccess.ReadWrite);
                        sZip.ExtractFile(extractAfterFile, fs);
                        fs.Flush();
                    }
                    fs.Dispose();

                    // 2, 执行extractBefore.bat
                    if (File.Exists(dir + "\\" + extractBeforeFile))
                    {
                        backgroundWorker1.ReportProgress(0, "running extractBefore.bat");
                        executeBat(dir + "\\" + extractBeforeFile);
                    }

                    // 3，读取配置文件
                    backgroundWorker1.ReportProgress(0, "reading package config.");
                    XmlDocument doc = new XmlDocument();
                    doc.Load(dir + "\\" + configFile);
                    XmlNodeList nodes = doc.SelectNodes("packageConfigs/extractpath/*");
                    if (nodes.Count > 0)
                    {
                        foreach (XmlNode node in nodes)
                        {
                            extractpaths.Add(node.Name, node.InnerText);
                        }
                    }

                    if (extractpaths.Count > 0)
                    {
                        // 4，按照配置的解压路径解压文件
                        backgroundWorker1.ReportProgress(0, "=== extracting files ===");
                        string _oldFolderName, _extractPDir, _extractPath, _extractDir;
                        for (int i = 0; i < sZip.ArchiveFileData.Count; i++)
                        {
                            ArchiveFileInfo arch = sZip.ArchiveFileData[i];
                            int t = arch.FileName.IndexOf("\\");
                            if (t != -1)
                            {
                                _oldFolderName = arch.FileName.Substring(0, t);
                                _extractPDir = extractpaths[_oldFolderName].ToString();
                                _extractPath = _extractPDir + arch.FileName.Substring(_oldFolderName.Length, arch.FileName.Length - _oldFolderName.Length);
                                _extractDir = Path.GetDirectoryName(_extractPath);

                                if (!Directory.Exists(_extractDir))
                                    Directory.CreateDirectory(_extractDir);

                                if (!arch.IsDirectory)
                                    sZip.ExtractFile(arch.Index, File.Create(_extractPath));

                                backgroundWorker1.ReportProgress(0, _extractPath);
                            }
                            else if (extractpaths.ContainsKey(arch.FileName))
                            {
                                sZip.ExtractFiles(extractpaths[arch.FileName].ToString(), arch.Index);
                                backgroundWorker1.ReportProgress(0, extractpaths[arch.FileName].ToString() + "\\" + arch.FileName);
                            }
                        }
                        backgroundWorker1.ReportProgress(0, "========================");
                    }

                    // 5, 执行extractAfter.bat
                    if (File.Exists(dir + "\\" + extractAfterFile))
                    {
                        backgroundWorker1.ReportProgress(0, "running extractAfter.bat");
                        executeBat(dir + "\\" + extractAfterFile);
                    }
                }
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            listBox1.Items.Add(string.Format("[{0}] {1}", DateTime.Now.ToString("yyyy/MM/dd HH:mm"), e.UserState.ToString()));
            listBox1.SelectedIndex = listBox1.Items.Count - 1;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            for (int i = 0; i < this.listBox1.Items.Count; i++)
            {
                Logger.Write(this.listBox1.Items[i].ToString());
            }
            this.Close();
        }

        private void executeBat(string file)
        {
            Process p = new Process();
            p.StartInfo.FileName = file;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();

            System.IO.StreamReader sr = p.StandardOutput;
            string s = string.Empty;
            while ((s = sr.ReadLine()) != null)
            {
                backgroundWorker1.ReportProgress(0, s);
            }
            sr.Dispose();
            p.WaitForExit();
            p.Dispose();
        }
    }
}
